﻿using DataProcess.Error;
using System;
using System.Collections.Generic;

namespace DataProcess
{
    namespace StringCase
    {

        /// <summary>
        /// 字符串数学表达式运算工具
        /// </summary>
        public sealed class StringToMath : TextAnalysis
        {
            protected override string BeforeTranslation(string raw)
            {
                char[] arr = raw.ToCharArray();
                for (int i = 0; i < arr.Length; i++)
                {
                    if (arr[i] == '-')
                    {
                        if (i == 0)
                        {
                            arr[i] = '~';
                        }
                        else if (!(arr[i - 1] >= '0' && arr[i - 1] <= '9'))
                        {
                            arr[i] = '~';
                        }
                    }
                }
                string str = new string(arr);
                for (int i = 0; i < str.Length; i++)
                {
                    if (!(str[i] >= '0' && str[i] <= '9' || str[i] == '.' || str[i] == '*' || str[i] == '/' || str[i] == '+' || str[i] == '-' || str[i] == '~'))
                    {
                        if (OnUnexpectedCharOut != null)
                        {
                            int c = OnUnexpectedCharOut(i, str[i], str);
                            if (c == 0)
                            {
                                str = str.Remove(i, 1);
                                i--;
                            }
                            else if (c > 0)
                            {
                                str = str.Remove(i, 1);
                                str = str.Insert(i, ((char)c).ToString());
                            }
                        }
                        else
                        {
                            str = str.Remove(i, 1);
                            i--;
                        }

                    }
                }


                return str;
            }
            public delegate void GetSimplestAction(string simplest);
            public delegate void GetEachBlockAction(string[] blocks, int deep);
            public delegate void ReplaceDetialAction(string old, string newstr);
            /// <summary>
            /// 出现错误字符时的方法
            /// </summary>
            /// <param name="index">当前位置</param>
            /// <param name="c">错误字符</param>
            /// <param name="raw">当前处理的字符串</param>
            /// <returns>返回0删除错误字符  返回>0 替换为对应的char值 返回<0 误操作 </returns>
            public delegate int UnexpectedCharAction(int index, char c, string raw);

            /// <summary>
            /// 出现错误字符时的操作
            /// </summary>
            public event UnexpectedCharAction OnUnexpectedCharOut;

            /// <summary>
            /// 当最简表达式得到
            /// </summary>
            public event GetSimplestAction OnSimpleGot;
            /// <summary>
            /// 每一块括号中内容获得时
            /// </summary>
            public event GetEachBlockAction OnBlockFound;
            /// <summary>
            /// 当置换表达式时
            /// </summary>
            public event ReplaceDetialAction OnReplacing;

            int deep = 0;
            protected override void GetEachBlockStr(params object[] objs)
            {
                if (OnBlockFound != null)
                {
                    string[] blocks = new string[objs.Length];
                    for (int i = 0; i < blocks.Length; i++)
                        blocks[i] = objs[i].ToString();
                    OnBlockFound(blocks, deep);
                }
                deep++;
            }
            protected override int OnReplace(string old, string newstr)
            {
                if (OnReplacing != null)
                {
                    OnReplacing(old, newstr);
                }
                return base.OnReplace(old, newstr);
            }
            protected override void GetSimplestStr(params object[] objs)
            {
                if (OnSimpleGot != null)
                {
                    OnSimpleGot(objs[0].ToString());
                }
                deep = 0;
            }
            protected override string TranslationAction(char sign, string front, string behind)
            {
                double res = 0;
                front = front.Replace("~", "-");
                behind = behind.Replace("~", "-");
                switch (sign)
                {
                    case '+':
                        res = double.Parse(front) + double.Parse(behind);
                        break;
                    case '-':
                        res = double.Parse(front) - double.Parse(behind);
                        break;
                    case '*':
                        res = double.Parse(front) * double.Parse(behind);
                        break;
                    case '/':
                        res = double.Parse(front) / double.Parse(behind);
                        break;
                    default:
                        throw new Exception("错误符号");
                }
                return res.ToString();
            }
            public double? Calculate(string text)
            {
                string[] p = Analysis(text, null, ("(", ")"), new char[] { '*', '/' }, new char[] { '+', '-' });
                if (p.Length > 0)
                    return double.Parse(p[0]);
                else
                    return null;


            }


        }


        /// <summary>
        /// 文本分析基类
        /// </summary>
        public abstract class TextAnalysis
        {
            /// <summary>
            /// 转译前处理
            /// </summary>
            /// <param name="raw">待处理文本</param>
            /// <returns></returns>
            protected virtual string BeforeTranslation(string raw)
            {
                return raw;
            }
            /// <summary>
            /// 翻译操作
            /// </summary>
            /// <param name="raw">待处理文本</param>
            /// <param name="signs">优先级的运算符处理</param>
            /// <returns>返回翻译后的文本</returns>
            protected virtual string Translation(string raw, char[][] signs)
            {
                raw = BeforeTranslation(raw);
                List<char> arr = new List<char>();
                foreach (char[] i in signs)
                {
                    arr.AddRange(i);
                }
                List<string> items = new List<string>(raw.Split(arr.ToArray()));
                List<char> Fuhao = getAllbaseSymbol(raw, arr);
                if (items.Count > 0)
                {
                    foreach (char[] chars in signs)
                    {
                        if (items.Count == 1)
                            return items[0];
                        for (int i = 0; i < Fuhao.Count; i++)
                        {
                            foreach (char c in chars)
                            {
                                if (Fuhao[i] == c)
                                {
                                    items.Insert(i, TranslationAction(c, items[i], items[i + 1]));
                                    items.RemoveRange(i + 1, 2);
                                    Fuhao.RemoveAt(i);
                                    i--;
                                    break;
                                }
                            }
                        }
                    }
                }
                return items[0];
            }
            /// <summary>
            /// 置换后的最简字符串得到时触发的方法
            /// </summary>
            /// <param name="objs">最简字符串：objs[0]</param>
            protected virtual void GetSimplestStr(params object[] objs)
            {

            }
            /// <summary>
            /// 每一块内字符串获取触发的方法
            /// </summary>
            /// <param name="objs">所有块字符串</param>
            protected virtual void GetEachBlockStr(params object[] objs)
            {

            }
            /// <summary>
            /// 置换时触发的方法
            /// </summary>
            /// <param name="old">原始字符串</param>
            /// <param name="newstr">置换后的字符串</param>
            /// <returns>大于0即确认置换，否则取消置换</returns>
            protected virtual int OnReplace(string old, string newstr)
            {
                return 1;
            }
            /// <summary>
            /// 核心翻译方法
            /// </summary>
            /// <param name="sign">当前运算符</param>
            /// <param name="front">运算符前文本</param>
            /// <param name="behind">运算符后文本</param>
            /// <returns></returns>
            protected abstract string TranslationAction(char sign, string front, string behind);
            private List<char> getAllbaseSymbol(string a, IEnumerable<char> signs)
            {
                List<char> Fuhao = new List<char>();
                char[] b = a.ToCharArray();
                foreach (char x in b)
                {
                    foreach (var c in signs)
                    {
                        if (c == x)
                        {
                            Fuhao.Add(x);
                            break;
                        }
                    }
                }
                return Fuhao;
            }
            char[][] Signs;
            /// <summary>
            /// 置换代替源字符串
            /// </summary>
            /// <param name="source"></param>
            /// <param name="block"></param>
            /// <returns></returns>
            protected virtual string TextReplace(string source, ValueTuple<string, string> block)
            {
                string result = StringDealer.MidInAndReplace(source, block.Item1, block.Item2, ReplaceAction, GetSimplestStr, GetEachBlockStr, OnReplace);
                return result;
            }
            string ReplaceAction(string before, string after, string mid, string nowstr)
            {
                return Translation(mid, Signs);
            }
            /// <summary>
            /// 分析
            /// </summary>
            /// <param name="raw">待分析字符串</param>
            /// <param name="cutchars">分割字符</param>
            /// <param name="blocksign">块标记</param>
            /// <param name="signs">运算符，根据优先级</param>
            /// <returns></returns>
            public virtual string[] Analysis(string raw, char[] cutchars, ValueTuple<string, string> blocksign, params char[][] signs)
            {
                Signs = signs;
                string[] singles;
                if (cutchars != null)
                {
                    singles = raw.Split(cutchars);
                }
                else
                    singles = new string[] { raw };
                for (int i = 0; i < singles.Length; i++)
                {
                    string temp = singles[i];
                    temp = TextReplace(singles[i], blocksign);
                    singles[i] = Translation(temp, signs);
                }
                Signs = null;
                return singles;
            }

        }
        /// <summary>
        /// 从字符串中提取数字
        /// </summary>
        public class NumbersDealer
        {
            private enum type
            {
                Number, String
            }

            private string[] w, n;
            /// <summary>
            /// 字符串中的非数字字段
            /// </summary>
            public string[] Words => w;
            /// <summary>
            /// 字符串中的数字
            /// </summary>
            public double[] Numbers
            {
                get
                {
                    double[] a = new double[n.Length];
                    int i = 0;
                    foreach (string ns in n)
                    {
                        a[i] = double.Parse(ns);
                        i++;
                    }
                    return a;
                }
            }

            private string an;
            /// <summary>
            /// 将要分析的原始字符串，设置后就会自动进行分析，即可调用
            /// </summary>
            public string Orgin
            {
                get => an;
                set
                {
                    an = value;
                    switch (hasPoint)
                    {
                        case true:
                            Analyse(an);
                            break;
                        case false:
                            IntAnalyse(an);
                            break;
                    }

                }
            }
            /// <summary>
            /// 得到的数字部分是否存在小数点
            /// </summary>
            public bool hasPoint = false;
            /// <summary>
            /// 初始化
            /// </summary>
            /// <param name="orgin">需要分析的字符串</param>
            /// <param name="haspoint">是否存在小数点</param>
            public NumbersDealer(string orgin, bool haspoint)
            {
                hasPoint = haspoint;
                Orgin = orgin;
            }
            private string GetLast(char[] t, int last, int index)
            {
                return new string(t, last, index - last);
            }

            private void Analyse(string T)
            {
                if (T.Length == 0)
                {
                    throw new StringCaseException("字符串长度不足");
                }

                List<string> num = new List<string>();
                List<string> word = new List<string>();
                char[] tmp = T.ToCharArray();
                bool isnum = tmp[0] >= '0' && tmp[0] <= '9';
                bool haspoint = false;
                int last = 0;
                for (int i = 1; i < tmp.Length; i++)
                {
                    if (isnum == true)
                    {
                        if (tmp[i] < '0' || tmp[i] > '9')
                        {
                            if (tmp[i] == '.' && haspoint == false)
                            {
                                haspoint = true;
                            }
                            else
                            {
                                num.Add(GetLast(tmp, last, i));
                                last = i;
                                isnum = false;
                                haspoint = false;
                            }
                        }
                    }
                    else
                    {
                        if (tmp[i] >= '0' && tmp[i] <= '9')
                        {
                            word.Add(GetLast(tmp, last, i));
                            last = i;
                            isnum = true;
                            haspoint = false;
                        }
                    }
                }
                w = word.ToArray();
                n = num.ToArray();
            }
            private void IntAnalyse(string T)
            {
                if (T.Length == 0)
                {
                    throw new StringCaseException("字符串长度不足");
                }

                List<string> num = new List<string>();
                List<string> word = new List<string>();
                char[] tmp = T.ToCharArray();
                bool isnum = tmp[0] >= '0' && tmp[0] <= '9';
                int last = 0;
                for (int i = 1; i < tmp.Length; i++)
                {
                    if (isnum == true)
                    {
                        if (tmp[i] < '0' || tmp[i] > '9')
                        {
                            num.Add(GetLast(tmp, last, i));
                            last = i;
                            isnum = false;
                        }
                    }
                    else
                    {
                        if (tmp[i] >= '0' && tmp[i] <= '9')
                        {
                            word.Add(GetLast(tmp, last, i));
                            last = i;
                            isnum = true;
                        }
                    }
                }
                w = word.ToArray();
                n = num.ToArray();
            }
        }
        /// <summary>
        /// 常规字符串处理
        /// </summary>
        public class StringDealer
        {
            /// <summary>
            /// 以yyyyMMdd的格式来产生自定义的DateTime
            /// </summary>
            /// <param name="s"></param>
            /// <returns></returns>
            public static DateTime ChangeToDateTime(string s)
            {
                return DateTime.ParseExact(s, "yyyyMMdd", System.Globalization.CultureInfo.InvariantCulture);
            }
            /// <summary>
            /// 特定字符串在某字符串中出现的次数
            /// </summary>
            /// <param name="words">某字符串</param>
            /// <param name="key">特定字符串</param>
            /// <returns></returns>
            public static int TotalWordNum(string words, string key)
            {
                int total = 0;
                int tmp = words.IndexOf(key);
                while (tmp != -1)
                {
                    total++;
                    tmp = words.IndexOf(key);
                    words = words.Remove(0, tmp + key.Length);
                }
                return total;

            }

            public delegate string ReplaceAction(string before, string after, string mid, string nowstr);
            public delegate void OutDataAction(params object[] objs);

            /// <summary>
            /// 截取字符串并置换
            /// </summary>
            /// <param name="word">待处理字符串</param>
            /// <param name="before">块前字符串</param>
            /// <param name="after">块后字符串</param>
            /// <param name="replace">置换方法</param>
            /// <param name="simplest">结束时获取的最简字符串方法</param>
            /// <param name="eachblock">截取到的每一个最简字符串方法</param>
            /// <returns></returns>
            public static string MidInAndReplace(string word, string before, string after, ReplaceAction replace, OutDataAction simplest = null, OutDataAction eachblock = null, Comparison<string> onreplace = null)
            {
                string s = word;
                while (true)
                {
                    string[] md = MidIn(s, before, after);
                    if (md.Length == 0)
                    {
                        if (simplest != null)
                        {
                            simplest(s);
                        }
                        break;
                    }
                    if (eachblock != null)
                    {
                        eachblock(md);
                    }
                    foreach (var i in md)
                    {
                        string old = s;
                        string newstr = s.Replace(before + i + after, replace(before, after, i, s));
                        if (onreplace != null)
                        {
                            if (onreplace(old, newstr) > 0)
                                s = newstr;
                        }
                        else
                            s = newstr;
                    }
                }
                return s;
            }

            static bool checkBehindForSame(char[] orgin, int from, char[] target)
            {
                if (target.Length + from > orgin.Length)
                    return false;
                string check = new string(orgin, from, target.Length);
                return check.Equals(new string(target));
            }
            /// <summary>
            /// 截取字符串
            /// </summary>
            /// <param name="words">待处理字符串</param>
            /// <param name="before">块前字符串</param>
            /// <param name="after">块后字符串</param>
            /// <returns></returns>
            public static string[] MidIn(string words, string before, string after)
            {
                return MidIn(words.ToCharArray(), before.ToCharArray(), after.ToCharArray());
            }

            /// <summary>
            /// 截取字符串
            /// </summary>
            /// <param name="words">待处理字符串</param>
            /// <param name="before">块前字符串</param>
            /// <param name="after">块后字符串</param>
            /// <returns>返回最内部块</returns>
            public static string[] MidIn(char[] words, char[] before, char[] after)
            {

                int last = -1;
                List<string> results = new List<string>();
                bool issame = new string(before).Equals(new string(after));
                for (int i = 0; i < words.Length; i++)
                {
                    char c = words[i];
                    if (before[0] == c && last < 0 || !issame && before[0] == c)
                    {
                        if (checkBehindForSame(words, i, before))
                        {
                            last = i + before.Length;
                            continue;
                        }
                    }
                    if (last >= 0 && i - last >= 0)
                    {
                        if (c == after[0])
                        {
                            if (checkBehindForSame(words, i, after))
                            {
                                results.Add(new string(words, last, i - last));
                                last = -1;
                            }
                        }
                    }
                }
                return results.ToArray();


            }
        }
    }
}
